package educar.models;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;

import educar.db.JPA;

public class Student {
	
	private String dni;
	private String nro_alumno;
	private String nombre;
	private String apellido;
	private User user; 
	private String sexo; 
	private String direccion;
	private String telefono; 
	private String email;
	private String fecha_nac;
	private int edad;
	private static JPA jpa = new JPA();
	
	/**
	 * metodo constructor de la clase, crea un nuevo alumno
	 * @param newDni "String que contiene el nuevo dni del alumno" 
	 * @param newNro_alumno "int que asigna un nuevo numero unico de alumno"
	 * @param newNombre "String que contiene el nuevo nombre del alumno" 
	 * @param newApellido "String que contiene el nuevo apellido del alumno" 
	 * @param newUser "String que contiene el nuevo nombre de usuario del alumno" 
	 * @param newSexo "String que contiene el nuevo sexo del alumno" 
	 * @param newDireccion "String que contiene la nueva direccion del alumno" 
	 * @param newTelefono "String que contiene el nuevo telefono del alumno" 
	 * @param newEmail "String que contiene el nuevo email del alumno" 
	 * @param newFecha_nac "String que contiene el nuevo dni del alumno de esta forma yyyy-mm-dd" 
	 * @param newEdad "int que contine la nueva edad del alumno, obtenida a traves del metodo Student.edad(fecha_nac)"
	 */
	public Student(String newNro_alumno,String newDni,String newNombre,String newApellido,User newUser,String newSexo,
											String newDireccion,String newTelefono,String newEmail,String newFecha_nac){
		setDni(newDni);
		setNro_alumno(newNro_alumno);
		setNombre(newNombre);
		setApellido(newApellido);
		setUser(newUser);
		setSexo(newSexo);
		setDireccion(newDireccion);
		setTelefono(newTelefono);
		setEmail(newEmail);
		setFecha_nac(newFecha_nac);
		setEdad(edad(newFecha_nac));
	}
	
	/**
	 * permite establecer el dni a un alumno
	 * @param newDni "String que cotiene dni del alumno"
	 */
	public void setDni(String newDni){
		dni = newDni;
	}
	
	/**
	 * retorna el numero de dni del alumno
	 * @return String
	 */
	public String getDni(){
		return dni;
	}
	
	/**
	 * permite establecer el numero de alumno a un alumno
	 * @param newNro_alumno "int que contine numero de alumno"
	 */
	public void setNro_alumno(String newNro_alumno){
		nro_alumno = newNro_alumno;
	}
	/**
	 * retorna el numero de alumno
	 * @return int
	 */
	public String getNro_alumno(){
		return nro_alumno;
	}
	
	/**
	 * permite establecer el nombre a un alumno
	 * @param newNombre "String que cotiene nombre del alumno"
	 */
	public void setNombre(String newNombre){
		nombre = newNombre;
	}
	/**
	 * retorna el nombre
	 * @return String
	 */
	public String getNombre(){
		return nombre;
	}
	
	/**
	 * permite establecer el apellido a un alumno
	 * @param newApellido "String que cotiene apellido del alumno"
	 */
	public void setApellido(String newApellido){
		apellido = newApellido;
	}
	/**
	 * retorna el apellido
	 * @return String
	 */
	public String getApellido(){
		return apellido;
	}
	
	/**
	 * permite establecer un usuario a un alumno
	 * @param newUser "User que cotiene un usuario asociado al alumno"
	 */
	public void setUser(User newUser){
		user = newUser; 
	}
	/**
	 * retorna el usuario asociado al alumno
	 * @return User
	 */
	public User getUser(){
		return user;
	}
	
	/**
	 * permite establecer el sexo de un alumno
	 * @param newSexo "String que cotiene sexo del alumno"
	 */
	public void setSexo(String newSexo){
		sexo = newSexo;
	}
	/**
	 * retorna el sexo
	 * @return String
	 */
	public String getSexo(){
		return sexo;
	}
	
	/**
	 * permite establecer la direccion a un alumno
	 * @param newDireccion "String que cotiene direccion del alumno"
	 */
	public void setDireccion(String newDireccion){
		direccion = newDireccion;
	}
	/**
	 * retorna la direccion
	 * @return String
	 */
	public String getDireccion(){
		return direccion;
	}
	
	/**
	 * permite establecer el telefono a un alumno
	 * @param newTelefono "String que cotiene telefono del alumno"
	 */
	public void setTelefono(String newTelefono){
		telefono = newTelefono;
	}
	/**
	 * retorna el numero de telefono
	 * @return String
	 */
	public String getTelefono(){
		return telefono;
	}
	
	/**
	 * permite establecer el e-mail a un alumno
	 * @param newEmail "String que cotiene e-mail del alumno"
	 */
	public void setEmail(String newEmail){
		email = newEmail;
	}
	/**
	 * retorna el e-mail
	 * @return String
	 */
	public String getEmail(){
		return email;
	}
	
	/**
	 * permite establecer la fecha de nacimiento a un alumno
	 * @param newFecha_nac "String que cotiene fecha de nacimiento del alumno"
	 */
	public void setFecha_nac(String newFecha_nac){
		fecha_nac = newFecha_nac;
	}
	/**
	 * retorna la fecha de nacimiento
	 * @return String
	 */
	public String getFecha_nac(){
		return fecha_nac;
	}
	
	/**
	 * permite establecer la edad a un alumno
	 * @param newEdad "String que cotiene edad del alumno"
	 */
	public void setEdad(int newEdad){
		edad = newEdad;
	}
	
	/**
	 * retorna la edad
	 * @return int
	 */
	public int getEdad(){
		return edad;
	}

	
	/**
	 * Obtiene la lista de materias en las que esta esta anotado el alumno 
	 * @return Materia[]  arreglo con objetos materias
	 * @throws materiaNotFound "si alguna materia no se pudo cargar"
	 */
	public Materia[] materiasInscriptas() throws materiaNotFound {
		String[][] result = jpa.ResultSetToStringArray(jpa.showProyection("cursa", "cod_materia", "dni", getDni()));
		Materia[] materiasList = new Materia[result.length];
		for (int i=0;i<result.length;i++) {
			materiasList[i] = Materia.getMateriaByCodigo(result[i][0]);
		}		
		return materiasList;
	}
	
	
	/**
	 * Obtiene la lista de materias en la que se puede anotar el alumno
	 * @return Materia[]  arreglo con objetos materias
	 * @throws materiaNotFound "si alguna materia no se pudo cargar"
	 */
	public Materia[] materiasDisponibles() throws materiaNotFound {
		String[] by = {"dni"};
		String[] value = {getDni()};
		String[][] result = jpa.ResultSetToStringArray(jpa.showNotIn("materia", "cod_materia","cod_materia", "cursa", "cod_materia",by , value));
		Materia[] materias = new Materia[result.length];
		for(int i = 0; i < result.length; i++) {
			try {
				materias[i] = Materia.getMateriaByCodigo(result[i][0]);
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}
		return materias;
	}


	/**
	 * Permite guardar un alumno en la base de datos
	 * @return Logico con el resultado de la operacion
	 */
	public boolean save() {
		try {
			Student.getStudentByDni(dni);
			return false;
		} catch (studentNotFound e1) {
			String[] columns = { "dni", "nombre", "apellido", "username", "sexo", "direccion", "telefono", "email", "fecha_nac" };
			PreparedStatement stm = jpa.newRecord("alumno", columns);
			try {
				stm.setString(1, dni);
				stm.setString(2, nombre);
				stm.setString(3, apellido);
				stm.setString(4, user.getUsername());
				stm.setString(5, sexo);
				stm.setString(6, direccion);
				stm.setString(7, telefono);
				stm.setString(8, email);
				stm.setString(9, fecha_nac);
			} catch (SQLException e) {
				e.printStackTrace();
				return false;
			}
			jpa.create(stm);
			return true;
		}
	}
	
	/**
	 * actualiza los datos del objeto actual por la referencia en la base de datos
	 * @return boolean "si pudo hacer la operacion"
	 */
	public boolean update() {
		try {
			String[] columns = {"dni","nombre", "apellido", "username", "sexo", "direccion", "telefono", "email", "fecha_nac"};
			String[] value = {this.getDni(),nombre,apellido,user.getUsername(),sexo,direccion,telefono,email,fecha_nac};
			jpa.update("alumno", columns, value, "nro_alumno", getNro_alumno());
			return true;
		}
		catch(Exception ex) {
			return false;
		}
	}


	/**
	 * elimina de la base de datos el objeto actual
	 */
	public void destroy() {
		try {
			jpa.destroy("alumno", "dni", this.getDni());
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * dado un dni (que pertenece a la base de datos) devuelve el objeto con todas las intancias que hace referencia al mismo
	 * @param dni "String dni del docente"
	 * @return Student "Estudiante cargado"
	 * @throws studentNotFound "Si no existe el estudiante o el usuario asosiado a el"
	 */
	public static Student getStudentByDni(String dni) throws studentNotFound {
		ResultSet rs = null;
		Student s = null;		
		rs = jpa.getByField("alumno", "dni", dni);
		try {
			if (rs.next()) {
				s = new Student(rs.getString(1), (rs.getString(2)), rs.getString(3), rs.getString(4), User.getUserByUsername(rs.getString(5)), 
						rs.getString(6),rs.getString(7), rs.getString(8), rs.getString(9), rs.getString(10));
			} else {
				throw new studentNotFound();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (userNotFound e) {
			throw new studentNotFound();
		}
		return s;
	}

	

	/**
	 * Obtiene un alumno a partir del username del mismo
	 * @param username "username del alumno"
	 * @return "Student del alumno cargado"
	 * @throws studentNotFound "si el alumno no existe o el user no existe"
	 */
	public static Student getStudentByUsername(String username) throws studentNotFound {
		ResultSet rs = null;
		Student t = null;
		rs = jpa.getByField("alumno", "username", username);
		try {
			if (rs.next()) {
				t = new Student(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), User.getUserByUsername(rs.getString(5)), 
								      rs.getString(6), rs.getString(7), rs.getString(8), rs.getString(9), rs.getString(10));
			} else {
				throw new studentNotFound();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (userNotFound e) {
			throw new studentNotFound();
		}
		return t;
	}
	
	/**
	 * retorna matriz con la tabla alumno
	 * @return matriz de object con los datos de la tabla
	 */
	public static Object[][] getStudentTable() {
		Object[][] studentTalbe = jpa.ResultSetToArray(jpa.showAll("alumno"));
		return studentTalbe;
	}
	
	
	/**
	 * Obtengo las materias que cursa el alumno
	 * @return Materia[] arreglo de materias que cursa
	 */
	public Materia[] getStudentMateriaList() {
		String[][] materias = jpa.ResultSetToStringArray(jpa.getByField("cursa", "cod_materia", "dni", getDni()));
		Materia[] result = new Materia[materias.length];
		for (int i=0;i<result.length;i++) {
			try {
				result[i] = Materia.getMateriaByCodigo(materias[i][0]);
			} catch (materiaNotFound e) {
				e.printStackTrace();
			}
		}
		return result;
	}
	
	
	/**
	 * Funcion que calcula la edad actual a partir de la fecha de nacmiento
	 * @param fecha_nac "fecha de nacimiento en string yyyy-mm-dd"
	 * @return int "edad calculada al dia de hou"
	 */
	public static int edad(String fecha_nac) {		   
	    Date fechaActual = new Date();
	    SimpleDateFormat formato = new SimpleDateFormat("yyyy-MM-dd");
	    String hoy = formato.format(fechaActual);
	    String[] dat1 = fecha_nac.split("-");
	    String[] dat2 = hoy.split("-");
	    int anos = Integer.parseInt(dat2[0]) - Integer.parseInt(dat1[0]);
	    int mes = Integer.parseInt(dat2[1]) - Integer.parseInt(dat1[1]);
	    if (mes < 0) {
	      anos = anos - 1;
	    } else if (mes == 0) {
	      int dia = Integer.parseInt(dat2[2]) - Integer.parseInt(dat1[2]);
	      if (dia > 0) {
	        anos = anos - 1;
	      }
	    }
	    return anos;
	}
	
	
	/**
	 * Redefinicion del metodo toString para la clase
	 */
	public String toString() {
		return this.getDni()+" -- "+this.getApellido()+", "+this.getNombre();				
	}
	
	
	/**
	 * Metodo utilizado en la busqueda
	 * @param arg0 string a buscar
	 * @return boolean si es parecido o no
	 */
	public boolean comparar(String arg0) {
		String busq = arg0.toLowerCase();
		String ape = this.getApellido().toLowerCase();
		String nam = this.getNombre().toLowerCase();
		String dni = this.getDni().toLowerCase();
		return (busq.equals(ape) || busq.equals(nam) || busq.equals(dni));
	}
}
